BNUOJ 50395 Vertex Cover(搜索、最小点覆盖)

题意:

$2 \leq N \leq 500, 1 \leq M \leq \frac{n(n - 1)}{2},N个点M条边的无向图$
$对于每条边(u, v)总有min(u, v)\le30,求这个图的最小点覆盖集的大小$

分析:

$裸搜的话,每条边分别尝试它的2个端点,具体搜到多少完全不知道,复杂度是爆炸的$
$但是这个题有一个很好的性质,min(u, v)\le30,这样最小点覆盖集不会超过30$
$所以直接尝试去搜这30个点,尝试选或者不选(不选的话那么它连的所有点就都要选了)$
$不然这条边就没有点来覆盖了,这里要预处理一下这30个点所连的边$
$用bitset来预处理就好了,其实就是类似邻接表存一下图$
$搜的过程用bitset来保存选取的点覆盖集当作状态$
$看起来复杂度是2^{30},加上最优性剪枝,以及bitset优化,实际上跑得飞快$
$时间复杂度O(跑得过)$

代码:

//
//  Created by TaoSama on 2016-05-09
//  Copyright (c) 2016 TaoSama. All rights reserved.
//
#pragma comment(linker, "/STACK:102400000,102400000")
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <string>
#include <set>
#include <vector>
#include <bitset>

using namespace std;
#define pr(x) cout << #x << " = " << x << "  "
#define prln(x) cout << #x << " = " << x << endl
const int N = 1e5 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;

int n, m;
bitset<500> g[30];

void dfs(int u, int& ans, bitset<500> vs) {
    int cnt = vs.count();
    if(cnt >= ans) return;
    if(u == min(n, 30)) {ans = cnt; return;}
    if(vs[u]) dfs(u + 1, ans, vs);
    else {
        vs[u] = 1;
        dfs(u + 1, ans, vs); //涂
        vs[u] = 0;
        dfs(u + 1, ans, vs | g[u]); //不涂它,连的点就得涂
    }
}

int main() {
#ifdef LOCAL
    freopen("C:\\Users\\TaoSama\\Desktop\\in.txt", "r", stdin);
//  freopen("C:\\Users\\TaoSama\\Desktop\\out.txt","w",stdout);
#endif
    ios_base::sync_with_stdio(0);
    clock_t _ = clock();

    while(scanf("%d%d", &n, &m) == 2) {
        for(int i = 0; i < 30; ++i) g[i].reset();
        for(int i = 1; i <= m; ++i) {
            int u, v; scanf("%d%d", &u, &v);
            --u; --v;
            if(u > v) swap(u, v);
            g[u][v] = 1;
            if(v < u) g[v][u] = 1;
        }

        int ans = INF;
        dfs(0, ans, 0);
        printf("%d\n", ans);
    }

#ifdef LOCAL
    printf("\nTime cost: %.2fs\n", 1.0 * (clock() - _) / CLOCKS_PER_SEC);
#endif
    return 0;
}